﻿using System.Reflection;
using System.Reflection.Emit;

using zijian666.Core;

namespace zijian666.DI.Features;
internal class StartupFilter
{
    private static readonly Lazy<object?> LAZY_INSTANCE = new(CreateInstance, LazyThreadSafetyMode.ExecutionAndPublication);
    public static object? Instance => LAZY_INSTANCE.Value;

    public static Exception? Exception { get; private set; }

    /// <summary>
    /// 构建动态 StartupFilter 实例
    /// </summary>
    /// <remarks>
    /// <code>
    /// class StartupFilter : Microsoft.AspNetCore.Hosting.IStartupFilter
    /// {
    ///     private readonly Func&lt;Action&lt;IApplicationBuilder&gt;, Action&lt;IApplicationBuilder&gt;&gt; _next;
    ///
    ///     public StartupFilter(Func&lt;Action&lt;IApplicationBuilder&gt;, Action&lt;IApplicationBuilder&gt;&gt; next)
    ///     {
    ///         _next = next;
    ///     }
    ///
    ///     public Action&lt;IApplicationBuilder&gt; Configure(Action&lt;IApplicationBuilder&gt; next)
    ///     {
    ///         return _next(next);
    ///     }
    /// }
    /// </code>
    /// </remarks>
    public static object? CreateInstance()
    {
        try
        {
            var ifilter = InterfaceType;
            var ibuilder = AssemblyResolver.Default.GetTypes(x => x.FullName == "Microsoft.AspNetCore.Builder.IApplicationBuilder").FirstOrDefault();

            // 检查是否找到了接口类型
            if (ifilter == null || ibuilder == null)
            {
                return null;
            }


            var actionType = typeof(Action<>).MakeGenericType(ibuilder);
            var funcType = typeof(Func<,>).MakeGenericType(actionType, actionType);
            var nextHandler = typeof(StartupFilter).GetMethod("Next")!.MakeGenericMethod(ibuilder).CreateDelegate(funcType);

            // 程序集
            var assemblyName = new AssemblyName("DynamicAssembly");
            var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
            // 模块
            var moduleBuilder = assemblyBuilder.DefineDynamicModule("DynamicModule");
            // 类型
            var typeBuilder = moduleBuilder.DefineType("StartupFilter", TypeAttributes.NotPublic);
            typeBuilder.AddInterfaceImplementation(ifilter);
            // 字段
            var fieldBuilder = typeBuilder.DefineField("_next", funcType, FieldAttributes.Private);
            // 构造函数
            var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, [funcType]);
            var ilGeneratorForCtor = constructorBuilder.GetILGenerator();
            ilGeneratorForCtor.Emit(OpCodes.Ldarg_0);
            ilGeneratorForCtor.Emit(OpCodes.Ldarg_1);
            ilGeneratorForCtor.Emit(OpCodes.Stfld, fieldBuilder);
            ilGeneratorForCtor.Emit(OpCodes.Ret);
            // 方法 Configure
            var methodBuilder = typeBuilder.DefineMethod("Configure", MethodAttributes.Public | MethodAttributes.Virtual, actionType, new Type[] { actionType });
            var ilGeneratorForMethod = methodBuilder.GetILGenerator();
            ilGeneratorForMethod.Emit(OpCodes.Ldarg_0);
            ilGeneratorForMethod.Emit(OpCodes.Ldfld, fieldBuilder);
            ilGeneratorForMethod.Emit(OpCodes.Ldarg_1);
            ilGeneratorForMethod.Emit(OpCodes.Callvirt, funcType.GetMethod("Invoke")!);
            ilGeneratorForMethod.Emit(OpCodes.Ret);
            // 动态构建类型
            var type = typeBuilder.CreateType()!;
            return Activator.CreateInstance(type, nextHandler);
        }
        catch (Exception e)
        {
            Exception = e;
            return null;
        }
    }

    public static Type? InterfaceType => AssemblyResolver.Default.GetTypes(x => x.FullName == "Microsoft.AspNetCore.Hosting.IStartupFilter").FirstOrDefault();

    public static Action<T> Next<T>(Action<T> next)
    {
        return app =>
        {
            var provider = (IServiceProvider)typeof(T).GetProperty("ApplicationServices")!.GetValue(app, null)!;
            provider.Configure(app!);
            next(app);
        };
    }
}
